home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////
- //
- // DLL functions to get summary info from OLE 2.0 document files.
- //
- // Copyright © 1994-1995 Somar Software, All Rights Reserved
- // Send problem reports and comments to 72202.2574@compuserve.com
- // Visit the Somar Software WWW site at http://www.somar.com
- //
- // Change Log:
- // V1.5 95/03/25 Handle PID_TOTAL_EDITTIME (time < 1980-01-01)
- // V1.4 95/02/06 Add 32 bit version of DLL, documentation changes
- // V1.3 94/06/06 Change validity checking, because Excel 5.0 files
- // are slightly invalid
- // V1.2 94/03/01 Change STGM_SHARE_DENY_WRITE to STGM_SHARE_DENY_NONE, so
- // info can be obtained for files currently open in WinWord.
- // V1.1 94/01/22 Add wInitStatus parameter to SumInfoInit and SumInfoUninit,
- // to account for case where CoInitialize already called for
- // application.
- // Ensure SumInfoGetString returns zero terminated string.
- // Fix minor typos in documentation.
- // V1.0 94/01/20 Initial version.
- //
- // Example of usage:
- // WORD wInitStatus;
- // HANDLE hSumInfo;
- // char szTemp[256];
- // LPSTR szFilePath;
- // WORD yr, mon, day, hr, min, sec;
- // if (wInitStatus = SumInfoInit()) {
- // ... loop to process files ...
- // szFilePath = ...
- // if (hSumInfo = SumInfoOpenFile(szFilePath)) {
- // if (SumInfoGetString(hSumInfo, PID_TITLE, szTemp, 256)) {
- // ... do something with szTemp ...
- // }
- // if (SumInfoGetTime(hSumInfo, PID_LASTSAVED,
- // &yr, &mon, &day, &hr, &min, &sec)) {
- // ... do something with time ...
- // }
- // ...
- // SumInfoCloseFile(hSumInfo);
- // }
- // }
- // SumInfoUninit(wInitStatus);
- // }
- //
- // Reasons for failure:
- // SumInfoInit: out of memory
- // SumInfoOpenFile: out of memory
- // file not found
- // file is not an OLE 2.0 structured storage file
- // file does not contain OLE 2.0 summary info
- // OLE 2.0 summary info is incorrectly formatted
- // SumInfoGet... : specified property type is not available
- //
- ///////////////////////////////////////////////////////////////////////////
-
- #define STRICT
- #include <windows.h>
- #include <memory.h>
- #ifdef WIN32
- #include <objbase.h>
- #else
- #include <ole2ver.h>
- #include <storage.h>
- #include <compobj.h>
- #endif
- #pragma hdrstop
-
- // a temporary function was unreferenced and then removed by optimization
- // causing warning 4505
- #pragma warning(disable:4505)
-
- ///////////////////////////////////////////////////////////////////////////
- #ifdef WIN32
- #define DLLEXPORT __stdcall
- #else
- #define DLLEXPORT FAR PASCAL __export
- #define VT_I4 3
- #define VT_LPSTR 30
- #define VT_FILETIME 64
- #endif
-
- typedef struct _PROPVALUE {
- DWORD vtType;
- union {
- FILETIME vtTime;
- LONG vtLong;
- struct {
- DWORD cBytes;
- char ch[1];
- } vtBSTR;
- } vtValue;
- } PROPVALUE;
- typedef PROPVALUE FAR * LPPROPVALUE;
-
- typedef struct _SUMMARYINFO {
- DWORD cBytes;
- DWORD cProps;
- struct {
- DWORD propID;
- DWORD dwOffset;
- } aProps[1];
- } SUMMARYINFO;
- typedef SUMMARYINFO FAR * LPSUMINFO;
-
- LPPROPVALUE FindProperty(HANDLE hSumInfo, DWORD pid);
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" WORD DLLEXPORT SumInfoInit()
- {
- #ifndef WIN32
- DWORD dwVer = CoBuildVersion();
- if (rmm != HIWORD(dwVer)) return 0;
- #endif
-
- HRESULT hr = CoInitialize(NULL);
- SCODE scode = GetScode(hr);
- if (scode == S_OK) return 1;
- if (scode == S_FALSE) return 2;
- return 0;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" void DLLEXPORT SumInfoUninit(WORD wInitStatus)
- {
- #ifndef WIN32
- if (wInitStatus == 1)
- #endif
- CoUninitialize();
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" HANDLE DLLEXPORT SumInfoOpenFile(LPSTR szPath)
- {
- BOOL bResult = FALSE;
- LPSUMINFO lpSumInfo;
- DWORD i;
- DWORD dwBytesInSection;
- HRESULT hr;
- ULONG ulBytesRead;
- LARGE_INTEGER li;
- LPSTREAM pIStream;
- LPSTORAGE pIStorage;
- HGLOBAL hglb = NULL;
-
- struct {
- WORD byteOrder;
- WORD wFormat;
- WORD osVersion1;
- WORD osVersion2;
- CLSID classId;
- DWORD cSections;
- } PropHeader;
- struct {
- DWORD dwords[4];
- DWORD dwOffset;
- } FIDAndOffset;
- #ifdef WIN32
- WCHAR wzPath[MAX_PATH+1];
-
- if (mbstowcs(wzPath, szPath, MAX_PATH) == -1)
- return NULL;
- wzPath[MAX_PATH] = 0; // ensure null termination
-
- hr = StgOpenStorage(wzPath,
- NULL, STGM_READ | STGM_SHARE_DENY_NONE | STGM_PRIORITY,
- NULL, 0, &pIStorage);
- if (FAILED(hr)) return NULL;
-
- hr = pIStorage->OpenStream(L"\005SummaryInformation", NULL,
- STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
- #else
- hr = StgOpenStorage(szPath,
- NULL, STGM_READ | STGM_SHARE_DENY_NONE | STGM_PRIORITY,
- NULL, 0, &pIStorage);
- if (FAILED(hr)) return NULL;
-
- hr = pIStorage->OpenStream("\005SummaryInformation", NULL,
- STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
-
- #endif
- if (FAILED(hr)) goto ReleaseStorage;
-
- LISet32(li, 0);
- hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
- if (hr != NOERROR) goto ReleaseStream;
-
- hr = pIStream->Read(&PropHeader, 28, &ulBytesRead);
- if (hr != NOERROR || ulBytesRead != 28) goto ReleaseStream;
-
- if (PropHeader.byteOrder != 0xFFFE) goto ReleaseStream;
- if (PropHeader.wFormat != 0) goto ReleaseStream;
-
- for (i = 0; i < PropHeader.cSections; i++) {
- hr = pIStream->Read(&FIDAndOffset, 20, &ulBytesRead);
- if (hr != NOERROR || ulBytesRead != 20) goto ReleaseStream;
- if (FIDAndOffset.dwords[0] == 0XF29F85E0 &&
- FIDAndOffset.dwords[1] == 0X10684FF9 &&
- FIDAndOffset.dwords[2] == 0X000891AB &&
- FIDAndOffset.dwords[3] == 0XD9B3272B) break;
- }
- if (i >= PropHeader.cSections) goto ReleaseStream;
-
- LISet32(li, FIDAndOffset.dwOffset);
- hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
- if (hr != NOERROR) goto ReleaseStream;
-
- hr = pIStream->Read(&dwBytesInSection, 4, &ulBytesRead);
- if (hr != NOERROR || ulBytesRead != 4) goto ReleaseStream;
-
- hglb = GlobalAlloc(GPTR, dwBytesInSection);
- if (hglb == NULL) goto ReleaseStream;
- lpSumInfo = (LPSUMINFO) GlobalLock(hglb);
- if (lpSumInfo == NULL) goto Free;
-
- hr = pIStream->Seek(li, STREAM_SEEK_SET, NULL);
- if (hr != NOERROR) goto Unlock;
-
- hr = pIStream->Read(lpSumInfo, dwBytesInSection, &ulBytesRead);
- if (hr != NOERROR || ulBytesRead > dwBytesInSection) goto Unlock;
- // tbd: dwBytesInSection is long by 4 bytes for some Excel 5.0 files, so just
- // check that ulBytesRead is <= dwBytesInSection and not that they are equal
-
- GlobalUnlock(hglb);
-
- goto ReleaseStream;
-
- Unlock:
- GlobalUnlock(hglb);
-
- Free:
- GlobalFree(hglb);
- hglb = NULL;
-
- ReleaseStream:
- pIStream->Release();
-
- ReleaseStorage:
- pIStorage->Release();
-
- return hglb;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" void DLLEXPORT SumInfoCloseFile(HANDLE hSumInfo)
- {
- GlobalFree(hSumInfo);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" BOOL DLLEXPORT SumInfoGetString(HANDLE hSumInfo,
- DWORD pid,
- LPSTR lpStr,
- WORD cbStr)
- {
- LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
- if (lpProp == NULL) return FALSE;
- if (lpProp->vtType != VT_LPSTR) return FALSE;
- int len = (int) lpProp->vtValue.vtBSTR.cBytes;
- if (len > cbStr) len = cbStr;
- if (len <= 0) {
- *(lpStr) = '\0';
- }
- else {
- lstrcpyn(lpStr, lpProp->vtValue.vtBSTR.ch, len);
- *(lpStr + len - 1) = '\0'; // len includes terminating null
- }
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" BOOL DLLEXPORT SumInfoGetLong(HANDLE hSumInfo,
- DWORD pid,
- LPLONG lpLong)
- {
- LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
- if (lpProp == NULL) return FALSE;
- if (lpProp->vtType != VT_I4) return FALSE;
- *lpLong = lpProp->vtValue.vtLong;
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- extern "C" BOOL DLLEXPORT SumInfoGetTime(HANDLE hSumInfo,
- DWORD pid,
- LPWORD yr,
- LPWORD mon,
- LPWORD day,
- LPWORD hr,
- LPWORD min,
- LPWORD sec)
- {
- struct {
- unsigned int day : 5;
- unsigned int mon : 4;
- unsigned int yr : 7;
- } DosDate;
- struct {
- unsigned int sec2 : 5;
- unsigned int min : 6;
- unsigned int hr : 5;
- } DosTime;
- BOOL fBefore1980;
-
- #define JAN1980_HIGH 0x01A8E79F
- #define JAN1980_LOW 0xE1D58000
-
- LPPROPVALUE lpProp = FindProperty(hSumInfo, pid);
- if (lpProp == NULL) return FALSE;
- if (lpProp->vtType != VT_FILETIME) return FALSE;
-
- // If time < Jan 1, 1980, then add FILETIME of 1980/01/01 00:00:00.
- // This is necessary for CoFileTimeToDosDateTime to work.
- if (lpProp->vtValue.vtTime.dwHighDateTime < JAN1980_HIGH) {
- lpProp->vtValue.vtTime.dwLowDateTime += JAN1980_LOW;
- lpProp->vtValue.vtTime.dwHighDateTime += JAN1980_HIGH;
- if (lpProp->vtValue.vtTime.dwLowDateTime < JAN1980_LOW)
- lpProp->vtValue.vtTime.dwHighDateTime++; // overflow
- fBefore1980 = TRUE;
- }
- else fBefore1980 = FALSE;
-
- if (!CoFileTimeToDosDateTime(&lpProp->vtValue.vtTime,
- (LPWORD) &DosDate, (LPWORD) &DosTime))
- return FALSE;
-
- *yr = (WORD) (DosDate.yr + 1980);
- *mon = (WORD) DosDate.mon;
- *day = (WORD) DosDate.day;
- *hr = (WORD) DosTime.hr;
- *min = (WORD) DosTime.min;
- *sec = (WORD) (DosTime.sec2 * 2);
-
- if (fBefore1980) {
- // Suppose edittime is actually 1 day, 3 hours.
- // Then Y/M/D will be 1980/1/2 at this point.
- // Which should be tranlated to 0/0/1.
- // The code below also handles cases where edittime > 1 month or even 1 year.
- *yr = *yr - 1980;
- *mon = *mon - 1;
- *day = *day - 1;
- if (*mon == 0 && *yr > 0) {
- (*yr)--;
- *mon = 12;
- }
- if (*day == 0 && *mon > 0) {
- (*mon)--;
- switch (*mon) {
- case 1: *day = 31; break;
- case 2: *day = 28; break;
- case 3: *day = 31; break;
- case 4: *day = 30; break;
- case 5: *day = 31; break;
- case 6: *day = 30; break;
- case 7: *day = 31; break;
- case 8: *day = 31; break;
- case 9: *day = 30; break;
- case 10: *day = 31; break;
- case 11: *day = 30; break;
- case 12: *day = 31; break;
- }
- }
- }
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- LPPROPVALUE FindProperty(HANDLE hSumInfo, DWORD pid)
- {
- LPPROPVALUE lpProp;
- DWORD i;
- LPSUMINFO lpSumInfo = (LPSUMINFO) GlobalLock(hSumInfo);
- if (lpSumInfo == NULL) return FALSE;
- for (i = 0; i < lpSumInfo->cProps; i++) {
- if (lpSumInfo->aProps[i].propID == pid) {
- lpProp = (LPPROPVALUE) ((LPBYTE) lpSumInfo + lpSumInfo->aProps[i].dwOffset);
- GlobalUnlock(hSumInfo);
- return lpProp;
- }
- }
- GlobalUnlock(hSumInfo);
- return NULL;
- }
-